#pragma once
#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <string>
#include <ctime>
#include <stdarg.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>


using namespace std;

enum
{
    Debug = 0,
    Info,
    Warning,
    Error,
    Fatal
};

enum
{
    Screen = 10,
    OneFile,
    ClassFile
};

string LevelToString(int level)
{
    switch(level)
    {
        case Debug:
            return "Debug";
        case Info:
            return "Info";
        case Warning:
            return "Warning";
        case Error:
            return "Error";
        case Fatal:
            return "Fatal";
        default:
            return "Unkonw";
    }
}

const int defaultstyle = Screen;
const string default_filename = "log.";
const string logdir = "log";

class Log
{
public:
    Log()
        :style(defaultstyle)
        ,filename(default_filename)
    {
        mkdir(logdir.c_str(), 0775);
    }  

    void Enable(int sty)
    {
        style = sty;
    }
    
    string TimeStampExLocalTime()
    {
        time_t currtime = time(nullptr);
        struct tm *curr = localtime(&currtime);
        char time_buffer[1024];
        snprintf(time_buffer, sizeof(time_buffer), "%d-%d-%d_%d:%d:%d",\
          curr->tm_year + 1900, curr->tm_mon + 1, curr->tm_mday, curr->tm_hour,\
          curr->tm_min, curr->tm_sec);
        
        return time_buffer;
    }

    void WriteLogToOneFile(string &logname, string &message)
    {
        umask(0);
        int fd = open(logname.c_str(), O_WRONLY|O_CREAT|O_APPEND, 0664);
        if(fd < 0) return;
        write(fd, message.c_str(), sizeof(message));
        close(fd);
    }

    void WriteLogToClassFile(const string &levelstr, string &message)
    {
        string logname = logdir;
        logname += "/";
        logname += filename;
        logname += levelstr;

        WriteLogToOneFile(logname, message);
    }

    void WriteLog(string &levelstr, string &message)
    {
        switch(style)
        {
            case Screen:
                cout << message << endl;
                break;
            case OneFile:
                WriteLogToClassFile("all", message);
                break;
            case ClassFile:
                WriteLogToClassFile(levelstr, message);
                break;
            default:
                cout << "Unknow" << endl;
                break;
        }
    }

    void LogMessage(int level, const char *format, ...) // 日志接口
    {
        char right_buffer[1024];
        va_list args;
        va_start(args, format);
        // args 指向了可变参数部分
        vsnprintf(right_buffer, sizeof(right_buffer), format, args);
        va_end(args);

        char left_buffer[1024];
        string currtime = TimeStampExLocalTime();
        string levelstr = LevelToString(level);
        string idstr = to_string(getpid());
        snprintf(left_buffer, sizeof(left_buffer), "[%s][%s][%s]", \
        levelstr.c_str(), currtime.c_str(), idstr.c_str());

        // printf("%s: %s\n", left_buffer, right_buffer);
        string loginfo = left_buffer;
        loginfo += right_buffer;
        WriteLog(levelstr, loginfo);
    }

    ~Log()
    {}
private:
    int style;
    string filename;
};